use std::{fmt::Display, str::FromStr};

use clap::{Parser, Subcommand};

use crate::cli::verify_input_file;

#[derive(Debug, Subcommand)]
pub enum Subbase64Command {
    #[command(name = "encode", about = "code file to base64")]
    Encode(Base64EncodeOpts),
    #[command(name = "decode", about = "decode base64 to file")]
    Decode(Base64DecodeOpts),
}
#[derive(Debug, Parser)]
pub struct Base64EncodeOpts {
    #[arg(short, long, default_value = "-", value_parser = verify_input_file)]
    pub input: String,

    #[arg(short, long, default_value = "standard", value_parser = parse_base64_format)]
    pub format: Base64Format,
}
#[derive(Debug, Parser)]
pub struct Base64DecodeOpts {
    #[arg(short, long, default_value = "-",value_parser = verify_input_file)]
    pub input: String,

    #[arg(short, long, default_value = "standard", value_parser = parse_base64_format)]
    pub format: Base64Format,
}

#[derive(Debug, Clone, Copy)]
pub enum Base64Format {
    Standard,
    UrlSafe,
}

fn parse_base64_format(format: &str) -> Result<Base64Format, anyhow::Error> {
    format.parse()
}

impl FromStr for Base64Format {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "standard" => Ok(Self::Standard),
            "urlsafe" => Ok(Self::UrlSafe),
            _ => Err(anyhow::anyhow!("invalid format")),
        }
    }
}

impl Display for Base64Format {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(match self {
            Base64Format::Standard => "standard",
            Base64Format::UrlSafe => "urlsafe",
        })
    }
}
